#nullable enable

using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;

namespace PHMEE.EnergyEfficiency;

/// <summary>
/// TODO: 迁移到 MySQL 中，且不再将各设备各种油品的油耗列举，而是使用 JSON 列表等方式
/// </summary>
public sealed class LogAbstract
{
    #region 不需要用户输入的字段

    public DateTime Ts { get; set; }

    public Guid Id { get; set; }

    /// <summary>
    /// 创建时间（UTC）
    /// </summary>
    public DateTime CreationTime { get; set; }

    /// <summary>
    /// 最后修改时间（UTC）
    /// </summary>
    public DateTime LastModifiedTime { get; set; }

    // 在时序数据库中，DateTimeUtc 就是 Ts，没必要再开一个字段
    // public DateTime DateTimeUtc { get; set; }

    #endregion 不需要用户输入的字段

    #region Vessel

    public int IMO { get; set; }

    #endregion Vessel

    #region Date Time

    /// <summary>
    /// yyyy-MM-dd
    /// </summary>
    public string DateUTC { get; set; } = null!;

    /// <summary>
    /// HH:mm
    /// </summary>
    public string TimeUTC { get; set; } = null!;

    #endregion Date Time

    #region Voyage

    public string VoyageFrom { get; set; } = null!;

    public string VoyageTo { get; set; } = null!;

    public string VoyageNumber { get; set; } = null!;

    public string? OffhireReasons { get; set; }

    #endregion Voyage

    #region Event

    public LogAbstractEventType Event { get; set; }

    #endregion Event

    #region Time elapsed

    public float TimeSincePreviousReport { get; set; }

    public float TimeElapsedSailing { get; set; }

    public float TimeElapsedAnchoring { get; set; }

    public float TimeElapsedDP { get; set; }

    public float TimeElapsedIce { get; set; }

    public float TimeElapsedManeuvering { get; set; }

    public float TimeElapsedWaiting { get; set; }

    public float TimeElapsedLoadingUnloading { get; set; }

    public float TimeElapsedDrifting { get; set; }

    #endregion Time elapsed

    #region Distance

    public float Distance { get; set; }

    #endregion Distance

    #region Position

    public int LatitudeDegree { get; set; }

    public float LatitudeMinutes { get; set; }

    public LatitudeNorthSouth LatitudeNorthSouth { get; set; }

    public int LongitudeDegree { get; set; }

    public float LongitudeMinutes { get; set; }

    public LongitudeEastWest LongitudeEastWest { get; set; }

    #endregion Position

    #region Cargo

    public float CargoMt { get; set; }

    [JsonPropertyName("Cargo_m3")] // m 为小写
    public float CargoM3 { get; set; }

    public int Passengers { get; set; }

    // [TDProperty("occupied_lane_meter", TDPropertyType.Col, TDDataType.FLOAT)]
    // public float OccupiedLaneMeter { get; set; }

    public float CargoCEU { get; set; }

    public int CargoTotalTEU { get; set; }

    public int CargoTotalFullTEU { get; set; }

    public int CargoFullReeferTEU { get; set; }

    public int Reefer20Chilled { get; set; }

    public int Reefer40Chilled { get; set; }

    public int Reefer20Frozen { get; set; }

    public int Reefer40Frozen { get; set; }

    #endregion Cargo

    #region Consumption

    #region Main engines Consumption

    public float MEConsumptionHFO { get; set; }

    public float MEConsumptionLFO { get; set; }

    public float MEConsumptionMGO { get; set; }

    public float MEConsumptionMDO { get; set; }

    public float MEConsumptionLSHFO { get; set; }

    public float MEConsumptionLSLFO { get; set; }

    public float MEConsumptionLSMGO { get; set; }

    public float MEConsumptionULSFO2020 { get; set; }

    public float MEConsumptionULSLFO2020 { get; set; }

    public float MEConsumptionULSMDO2020 { get; set; }

    public float MEConsumptionULSMGO2020 { get; set; }

    public float MEConsumptionVLSFO2020 { get; set; }

    public float MEConsumptionVLSLFO2020 { get; set; }

    public float MEConsumptionLPGP { get; set; }

    public float MEConsumptionLPGB { get; set; }

    public float MEConsumptionLNG { get; set; }

    public float MEConsumptionM { get; set; }

    public float MEConsumptionE { get; set; }

    public float MEConsumptionO { get; set; }

    public string? MEConsumptionOType { get; set; }

    #endregion MainEngine Consumption

    #region Aux Engines Consumption

    public float AEConsumptionHFO { get; set; }

    public float AEConsumptionLFO { get; set; }

    public float AEConsumptionMGO { get; set; }

    public float AEConsumptionMDO { get; set; }

    public float AEConsumptionLSHFO { get; set; }

    public float AEConsumptionLSLFO { get; set; }

    public float AEConsumptionLSMGO { get; set; }

    public float AEConsumptionULSFO2020 { get; set; }

    public float AEConsumptionULSLFO2020 { get; set; }

    public float AEConsumptionULSMDO2020 { get; set; }

    public float AEConsumptionULSMGO2020 { get; set; }

    public float AEConsumptionVLSFO2020 { get; set; }

    public float AEConsumptionVLSLFO2020 { get; set; }

    public float AEConsumptionLPGP { get; set; }

    public float AEConsumptionLPGB { get; set; }

    public float AEConsumptionLNG { get; set; }

    public float AEConsumptionM { get; set; }

    public float AEConsumptionE { get; set; }

    public float AEConsumptionO { get; set; }

    public string? AEConsumptionOType { get; set; }

    #region AE Emergency Consumption

    public float AEEmrgConsHFO { get; set; }

    public float AEEmrgConsLFO { get; set; }

    public float AEEmrgConsMGO { get; set; }

    public float AEEmrgConsMDO { get; set; }

    public float AEEmrgConsLSHFO { get; set; }

    public float AEEmrgConsLSLFO { get; set; }

    public float AEEmrgConsLSMGO { get; set; }

    public float AEEmrgConsULSFO2020 { get; set; }

    public float AEEmrgConsULSLFO2020 { get; set; }

    public float AEEmrgConsULSMDO2020 { get; set; }

    public float AEEmrgConsULSMGO2020 { get; set; }

    public float AEEmrgConsVLSFO2020 { get; set; }

    public float AEEmrgConsVLSLFO2020 { get; set; }

    public float AEEmrgConsLPGP { get; set; }

    public float AEEmrgConsLPGB { get; set; }

    public float AEEmrgConsLNG { get; set; }

    public float AEEmrgConsM { get; set; }

    public float AEEmrgConsE { get; set; }

    public float AEEmrgConsO { get; set; }

    public string? AEEmrgConsOType { get; set; }

    #endregion AE Emergency Consumption

    #endregion Aux Engines Consumption

    #region Boilers Consumption

    public float BoilerConsumptionHFO { get; set; }

    public float BoilerConsumptionLFO { get; set; }

    public float BoilerConsumptionMGO { get; set; }

    public float BoilerConsumptionMDO { get; set; }

    public float BoilerConsumptionLSHFO { get; set; }

    public float BoilerConsumptionLSLFO { get; set; }

    public float BoilerConsumptionLSMGO { get; set; }

    public float BoilerConsumptionULSFO2020 { get; set; }

    public float BoilerConsumptionULSLFO2020 { get; set; }

    public float BoilerConsumptionULSMDO2020 { get; set; }

    public float BoilerConsumptionULSMGO2020 { get; set; }

    public float BoilerConsumptionVLSFO2020 { get; set; }

    public float BoilerConsumptionVLSLFO2020 { get; set; }

    public float BoilerConsumptionLPGP { get; set; }

    public float BoilerConsumptionLPGB { get; set; }

    public float BoilerConsumptionLNG { get; set; }

    public float BoilerConsumptionM { get; set; }

    public float BoilerConsumptionE { get; set; }

    public float BoilerConsumptionO { get; set; }

    public string? BoilerConsumptionOType { get; set; }

    #endregion Boilers Consumption

    #region Inert Gas Consumption

    public float InertGasConsumptionHFO { get; set; }

    public float InertGasConsumptionLFO { get; set; }

    public float InertGasConsumptionMGO { get; set; }

    public float InertGasConsumptionMDO { get; set; }

    public float InertGasConsumptionLSHFO { get; set; }

    public float InertGasConsumptionLSLFO { get; set; }

    public float InertGasConsumptionLSMGO { get; set; }

    public float InertGasConsumptionULSFO2020 { get; set; }

    public float InertGasConsumptionULSLFO2020 { get; set; }

    public float InertGasConsumptionULSMDO2020 { get; set; }

    public float InertGasConsumptionULSMGO2020 { get; set; }

    public float InertGasConsumptionVLSFO2020 { get; set; }

    public float InertGasConsumptionVLSLFO2020 { get; set; }

    public float InertGasConsumptionLPGP { get; set; }

    public float InertGasConsumptionLPGB { get; set; }

    public float InertGasConsumptionLNG { get; set; }

    public float InertGasConsumptionM { get; set; }

    public float InertGasConsumptionE { get; set; }

    public float InertGasConsumptionO { get; set; }

    public string? InertGasConsumptionOType { get; set; }

    #endregion Inert Gas Consumption

    #region Incinerators Consumption

    public float IncineratorConsumptionO { get; set; }

    public string? IncineratorConsumptionOType { get; set; }

    #endregion Incinerators Consumption

    #endregion Consumption

    #region ROB

    public float HFOROB { get; set; }

    public float LFOROB { get; set; }

    public float MGOROB { get; set; }

    public float MDOROB { get; set; }

    public float LSHFOROB { get; set; }

    public float LSLFOROB { get; set; }

    public float LSMGOROB { get; set; }

    public float ULSFO2020ROB { get; set; }

    public float ULSLFO2020ROB { get; set; }

    public float ULSMDO2020ROB { get; set; }

    public float ULSMGO2020ROB { get; set; }

    public float VLSFO2020ROB { get; set; }

    public float VLSLFO2020ROB { get; set; }

    public float LPGPROB { get; set; }

    public float LPGBROB { get; set; }

    public float LNGROB { get; set; }

    public float MethanolROB { get; set; }

    public float EthanolROB { get; set; }

    public float OROB { get; set; }

    public string? OROBType { get; set; }

    #endregion ROB

    #region Allocation of fuel amounts

    #region Cargo heating Consumption

    public float CargoHeatingConsumptionHFO { get; set; }

    public float CargoHeatingConsumptionLFO { get; set; }

    public float CargoHeatingConsumptionMGO { get; set; }

    public float CargoHeatingConsumptionMDO { get; set; }

    public float CargoHeatingConsumptionLSHFO { get; set; }

    public float CargoHeatingConsumptionLSLFO { get; set; }

    public float CargoHeatingConsumptionLSMGO { get; set; }

    public float CargoHeatingConsumptionULSFO2020 { get; set; }

    public float CargoHeatingConsumptionULSLFO2020 { get; set; }

    public float CargoHeatingConsumptionULSMDO2020 { get; set; }

    public float CargoHeatingConsumptionULSMGO2020 { get; set; }

    public float CargoHeatingConsumptionVLSFO2020 { get; set; }

    public float CargoHeatingConsumptionVLSLFO2020 { get; set; }

    public float CargoHeatingConsumptionLPGP { get; set; }

    public float CargoHeatingConsumptionLPGB { get; set; }

    public float CargoHeatingConsumptionLNG { get; set; }

    public float CargoHeatingConsumptionM { get; set; }

    public float CargoHeatingConsumptionE { get; set; }

    public float CargoHeatingConsumptionO { get; set; }

    public string? CargoHeatingConsumptionOType { get; set; }

    #endregion Cargo heating Consumption

    #region Diesel power packs of cargo pumps Consumption

    public float DPPCargoPumpConsumptionMDO { get; set; }

    public float DPPCargoPumpConsumptionO { get; set; }

    public string? DPPCargoPumpConsumptionOType { get; set; }

    #endregion Diesel power packs of cargo pumps Consumption

    #region DP Consumption

    public float DPConsumptionHFO { get; set; }

    public float DPConsumptionLFO { get; set; }

    public float DPConsumptionMGO { get; set; }

    public float DPConsumptionMDO { get; set; }

    public float DPConsumptionLSHFO { get; set; }

    public float DPConsumptionLSLFO { get; set; }

    public float DPConsumptionLSMGO { get; set; }

    public float DPConsumptionULSFO2020 { get; set; }

    public float DPConsumptionULSLFO2020 { get; set; }

    public float DPConsumptionULSMDO2020 { get; set; }

    public float DPConsumptionULSMGO2020 { get; set; }

    public float DPConsumptionVLSFO2020 { get; set; }

    public float DPConsumptionVLSLFO2020 { get; set; }

    public float DPConsumptionLPGP { get; set; }

    public float DPConsumptionLPGB { get; set; }

    public float DPConsumptionLNG { get; set; }

    public float DPConsumptionM { get; set; }

    public float DPConsumptionE { get; set; }

    public float DPConsumptionO { get; set; }

    public string? DPConsumptionOType { get; set; }

    #endregion DP Consumption

    #endregion Allocation of fuel amounts

    #region Machinery

    #region Reefer container

    public float ReeferWork { get; set; }

    public float ReeferSFOC { get; set; }

    public FuelType? ReeferFuelType { get; set; }

    public string? ReeferFuelBDN { get; set; }

    #endregion Reefer container

    #region Cargo cooling

    public float CargoCoolingWork { get; set; }

    public float CargoCoolingSFOC { get; set; }

    public FuelType? CargoCoolingFuelType { get; set; }

    public string? CargoCoolingFuelBDN { get; set; }

    #endregion Cargo cooling

    #region Discharge pump

    public float DischargePumpWork { get; set; }

    public float DischargePumpSFOC { get; set; }

    public FuelType? DischargePumpFuelType { get; set; }

    public string? DischargePumpFuelBDN { get; set; }

    #endregion Discharge pump

    #region Shore-Side Electricity

    public float ShoreSideElectricityReception { get; set; }

    #endregion Shore-Side Electricity

    #endregion Machinery

    public LogAbstract()
    {
    }
}

public static class LogAbstractExtensions
{
    /*
     * 按照目前（2024-03-28）的规范，DP 不影响 EEOI 和 CII，只对 MRV 报表填报有要求，所以获取油耗的方法均不考虑 DP
     */

    /// <summary>
    /// 根据 fuelType 获取 “包含应急油耗” 的总油耗
    /// </summary>
    /// <param name="logs"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    public static float GetTotalWithEmrgConsumptionByFuelType(this IEnumerable<LogAbstract> logs, FuelType fuelType)
    {
        float consumption = 0;
        
        foreach (var log in logs)
        {
            consumption += log.GetTotalWithEmrgConsumptionByFuelType(fuelType);
        }
        
        return consumption;
    }

    /// <summary>
    /// 根据 fuelType 获取 “包含应急油耗” 的总油耗
    /// </summary>
    /// <param name="log"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    public static float GetTotalWithEmrgConsumptionByFuelType(this LogAbstract log, FuelType fuelType)
    {
        // 不含应急油耗的总油耗
        float withoutEmrgConsumption = log.GetTotalConsumptionByFuelType(fuelType);
        // 应急油耗
        float emrgConsumption = log.GetAEEmrgConsByFuelType(fuelType);
        
        return withoutEmrgConsumption + emrgConsumption;
    }

    /// <summary>
    /// 根据 fuelType 获取总油耗（不含应急油耗）
    /// </summary>
    /// <param name="log"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public static float GetTotalConsumptionByFuelType(this LogAbstract log, FuelType fuelType)
    {
        float totalConsumption = 0;

        switch (fuelType)
        {
            case FuelType.HFO:
                totalConsumption += log.MEConsumptionHFO + log.AEConsumptionHFO + log.BoilerConsumptionHFO +
                                    log.InertGasConsumptionHFO;
                break;
            case FuelType.LFO:
                totalConsumption += log.MEConsumptionLFO + log.AEConsumptionLFO + log.BoilerConsumptionLFO +
                                    log.InertGasConsumptionLFO;
                break;
            case FuelType.MGO:
                totalConsumption += log.MEConsumptionMGO + log.AEConsumptionMGO + log.BoilerConsumptionMGO +
                                    log.InertGasConsumptionMGO;
                break;
            case FuelType.MDO:
                totalConsumption += log.MEConsumptionMDO + log.AEConsumptionMDO + log.BoilerConsumptionMDO +
                                    log.InertGasConsumptionMDO;
                break;
            case FuelType.LSHFO:
                totalConsumption += log.MEConsumptionLSHFO + log.AEConsumptionLSHFO + log.BoilerConsumptionLSHFO +
                                    log.InertGasConsumptionLSHFO;
                break;
            case FuelType.LSLFO:
                totalConsumption += log.MEConsumptionLSLFO + log.AEConsumptionLSLFO + log.BoilerConsumptionLSLFO +
                                    log.InertGasConsumptionLSLFO;
                break;
            case FuelType.LSMGO:
                totalConsumption += log.MEConsumptionLSMGO + log.AEConsumptionLSMGO + log.BoilerConsumptionLSMGO +
                                    log.InertGasConsumptionLSMGO;
                break;
            case FuelType.ULSFO2020:
                totalConsumption += log.MEConsumptionULSFO2020 + log.AEConsumptionULSFO2020 +
                                    log.BoilerConsumptionULSFO2020 + log.InertGasConsumptionULSFO2020;
                break;
            case FuelType.ULSLFO2020:
                totalConsumption += log.MEConsumptionULSLFO2020 + log.AEConsumptionULSLFO2020 +
                                    log.BoilerConsumptionULSLFO2020 + log.InertGasConsumptionULSLFO2020;
                break;
            case FuelType.ULSMDO2020:
                totalConsumption += log.MEConsumptionULSMDO2020 + log.AEConsumptionULSMDO2020 +
                                    log.BoilerConsumptionULSMDO2020 + log.InertGasConsumptionULSMDO2020;
                break;
            case FuelType.ULSMGO2020:
                totalConsumption += log.MEConsumptionULSMGO2020 + log.AEConsumptionULSMGO2020 +
                                    log.BoilerConsumptionULSMGO2020 + log.InertGasConsumptionULSMGO2020;
                break;
            case FuelType.VLSFO2020:
                totalConsumption += log.MEConsumptionVLSFO2020 + log.AEConsumptionVLSFO2020 +
                                    log.BoilerConsumptionVLSFO2020 + log.InertGasConsumptionVLSFO2020;
                break;
            case FuelType.VLSLFO2020:
                totalConsumption += log.MEConsumptionVLSLFO2020 + log.AEConsumptionVLSLFO2020 +
                                    log.BoilerConsumptionVLSLFO2020 + log.InertGasConsumptionVLSLFO2020;
                break;
            case FuelType.LPGP:
                totalConsumption += log.MEConsumptionLPGP + log.AEConsumptionLPGP + log.BoilerConsumptionLPGP +
                                    log.InertGasConsumptionLPGP;
                break;
            case FuelType.LPGB:
                totalConsumption += log.MEConsumptionLPGB + log.AEConsumptionLPGB + log.BoilerConsumptionLPGB +
                                    log.InertGasConsumptionLPGB;
                break;
            case FuelType.LNG:
                totalConsumption += log.MEConsumptionLNG + log.AEConsumptionLNG + log.BoilerConsumptionLNG +
                                    log.InertGasConsumptionLNG;
                break;
            case FuelType.Methanol:
                totalConsumption += log.MEConsumptionM + log.AEConsumptionM + log.BoilerConsumptionM +
                                    log.InertGasConsumptionM;
                break;
            case FuelType.Ethanol:
                totalConsumption += log.MEConsumptionE + log.AEConsumptionE + log.BoilerConsumptionE +
                                    log.InertGasConsumptionE;
                break;
            default:
                throw new Exception($"不支持的 FuelType {nameof(FuelType)}");
        }

        return totalConsumption;
    }

    /// <summary>
    /// 根据 fuelType 获取总油耗（不含应急油耗）
    /// </summary>
    /// <param name="logs"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    public static float GetTotalConsumptionByFuelType(this IEnumerable<LogAbstract> logs, FuelType fuelType)
    {
        float totalConsumption = 0;

        foreach (var log in logs)
        {
            totalConsumption += log.GetTotalConsumptionByFuelType(fuelType);
        }

        return totalConsumption;
    }

    /// <summary>
    /// 根据 fuelTypes 获取总油耗（不含应急油耗）
    /// </summary>
    /// <param name="logs"></param>
    /// <param name="fuelTypes"></param>
    /// <returns></returns>
    public static float GetTotalConsumptionByFuelTypes(this IEnumerable<LogAbstract> logs, List<FuelType> fuelTypes)
    {
        float totalConsumption = 0;

        foreach (var log in logs)
        {
            foreach (var fuelType in fuelTypes)
            {
                totalConsumption += log.GetTotalConsumptionByFuelType(fuelType);
            }
        }

        return totalConsumption;
    }

    /// <summary>
    /// 根据 fuelType 获取 Cargo Heating 油耗（不含应急油耗）
    /// </summary>
    /// <param name="log"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public static float GetCargoHeatingConsumptionByFuelType(this LogAbstract log, FuelType fuelType)
    {
        switch (fuelType)
        {
            case FuelType.HFO:
                return log.CargoHeatingConsumptionHFO;
            case FuelType.LFO:
                return log.CargoHeatingConsumptionLFO;
            case FuelType.MGO:
                return log.CargoHeatingConsumptionMGO;
            case FuelType.MDO:
                return log.CargoHeatingConsumptionMDO;
            case FuelType.LSHFO:
                return log.CargoHeatingConsumptionLSHFO;
            case FuelType.LSLFO:
                return log.CargoHeatingConsumptionLSLFO;
            case FuelType.LSMGO:
                return log.CargoHeatingConsumptionLSMGO;
            case FuelType.ULSFO2020:
                return log.CargoHeatingConsumptionULSFO2020;
            case FuelType.ULSLFO2020:
                return log.CargoHeatingConsumptionULSLFO2020;
            case FuelType.ULSMDO2020:
                return log.CargoHeatingConsumptionULSMDO2020;
            case FuelType.ULSMGO2020:
                return log.CargoHeatingConsumptionULSMGO2020;
            case FuelType.VLSFO2020:
                return log.CargoHeatingConsumptionVLSFO2020;
            case FuelType.VLSLFO2020:
                return log.CargoHeatingConsumptionVLSLFO2020;
            case FuelType.LPGP:
                return log.CargoHeatingConsumptionLPGP;
            case FuelType.LPGB:
                return log.CargoHeatingConsumptionLPGB;
            case FuelType.LNG:
                return log.CargoHeatingConsumptionLNG;
            case FuelType.Methanol:
                return log.CargoHeatingConsumptionM;
            case FuelType.Ethanol:
                return log.CargoHeatingConsumptionE;
            default:
                throw new Exception($"不支持的 FuelType {nameof(FuelType)}");
        }
    }

    /// <summary>
    /// 根据 fuelType 获取 Cargo Heating 油耗（不含应急油耗）
    /// </summary>
    /// <param name="logs"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    public static float GetCargoHeatingConsumptionByFuelType(this IEnumerable<LogAbstract> logs, FuelType fuelType)
    {
        float totalConsumption = 0;

        foreach (var log in logs)
        {
            totalConsumption += log.GetCargoHeatingConsumptionByFuelType(fuelType);
        }

        return totalConsumption;
    }

    /// <summary>
    /// 根据 fuelType 获取 DPPCargoPump 油耗（不含应急油耗）
    /// </summary>
    /// <param name="log"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public static float GetDPPCargoPumpConsumptionByFuelType(this LogAbstract log, FuelType fuelType)
    {
        switch (fuelType)
        {
            case FuelType.MDO:
                return log.DPPCargoPumpConsumptionMDO;
            case FuelType.HFO:
            case FuelType.LFO:
            case FuelType.MGO:
            case FuelType.LSHFO:
            case FuelType.LSLFO:
            case FuelType.LSMGO:
            case FuelType.ULSFO2020:
            case FuelType.ULSLFO2020:
            case FuelType.ULSMDO2020:
            case FuelType.ULSMGO2020:
            case FuelType.VLSFO2020:
            case FuelType.VLSLFO2020:
            case FuelType.LPGP:
            case FuelType.LPGB:
            case FuelType.LNG:
            case FuelType.Methanol:
            case FuelType.Ethanol:
                return 0f;
            default:
                throw new Exception($"不支持的 FuelType {nameof(FuelType)}");
        }
    }

    /// <summary>
    /// 根据 fuelType 获取 DPPCargoPump 油耗（不含应急油耗）
    /// </summary>
    /// <param name="logs"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    public static float GetDPPCargoPumpConsumptionByFuelType(this IEnumerable<LogAbstract> logs, FuelType fuelType)
    {
        float totalConsumption = 0;

        foreach (var log in logs)
        {
            totalConsumption += log.GetDPPCargoPumpConsumptionByFuelType(fuelType);
        }

        return totalConsumption;
    }

    /// <summary>
    /// 根据 fuelType 获取存量油量 ROB
    /// </summary>
    /// <param name="log"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public static float GetROBByFuelType(this LogAbstract log, FuelType fuelType)
    {
        switch (fuelType)
        {
            case FuelType.HFO:
                return log.HFOROB;
            case FuelType.LFO:
                return log.LFOROB;
            case FuelType.MGO:
                return log.MGOROB;
            case FuelType.MDO:
                return log.MDOROB;
            case FuelType.LSHFO:
                return log.LSHFOROB;
            case FuelType.LSLFO:
                return log.LSLFOROB;
            case FuelType.LSMGO:
                return log.LSMGOROB;
            case FuelType.ULSFO2020:
                return log.ULSFO2020ROB;
            case FuelType.ULSLFO2020:
                return log.ULSLFO2020ROB;
            case FuelType.ULSMDO2020:
                return log.ULSMDO2020ROB;
            case FuelType.ULSMGO2020:
                return log.ULSMGO2020ROB;
            case FuelType.VLSFO2020:
                return log.VLSFO2020ROB;
            case FuelType.VLSLFO2020:
                return log.VLSLFO2020ROB;
            case FuelType.LPGP:
                return log.LPGPROB;
            case FuelType.LPGB:
                return log.LPGBROB;
            case FuelType.LNG:
                return log.LNGROB;
            case FuelType.Methanol:
                return log.MethanolROB;
            case FuelType.Ethanol:
                return log.EthanolROB;
            default:
                throw new Exception($"不支持的 FuelType {nameof(FuelType)}");
        }
    }

    /// <summary>
    /// 根据不同船型获取不同的 MCargo 值
    /// </summary>
    /// <param name="logAbstract"></param>
    /// <param name="vesselType"></param>
    /// <returns></returns>
    public static float GetMCargo(this LogAbstract logAbstract, VesselType vesselType)
    {
        switch (vesselType)
        {
            case VesselType.Tanker:
            case VesselType.GasCarrier:
            case VesselType.BulkCarrier:
            case VesselType.GeneralCargoShip:
            case VesselType.RefrigeratedCargoCarrier:
            case VesselType.CombinationCarrier:
                return logAbstract.CargoMt;

            case VesselType.LNGCarrier:
            case VesselType.RoRoCargoShip:
                return logAbstract.CargoM3;

            case VesselType.CruisePassengerShip:
            case VesselType.RoRoPassengerShip:
            case VesselType.RoRoPassengerShipHighSpeedCraftDesignedToSOLASChapterX:
                return logAbstract.Passengers;

            case VesselType.RoRoCargoShipVehicleCarrier:
                return logAbstract.CargoCEU;

            case VesselType.ContainerShip:
                return logAbstract.CargoTotalTEU * 38.3f;

            default:
                return 0f;
        }
    }

    #region 应急油耗

    /// <summary>
    /// 根据 fuelType 获取 LogAbstract 集合的副机机组总应急油耗
    /// </summary>
    /// <param name="logs"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    public static float GetAEEmrgTotalConsumptionByFuelType(this IEnumerable<LogAbstract> logs, FuelType fuelType)
    {
        float totalConsumption = 0;

        foreach (var log in logs)
        {
            totalConsumption += log.GetAEEmrgConsByFuelType(fuelType);
        }

        return totalConsumption;
    }

    /// <summary>
    /// 根据 fuelType 获取单个 LogAbstract 副机机组应急油耗
    /// </summary>
    /// <param name="log"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    private static float GetAEEmrgConsByFuelType(this LogAbstract log, FuelType fuelType)
    {
        switch (fuelType)
        {
            case FuelType.HFO:
                return log.AEEmrgConsHFO;
            case FuelType.LFO:
                return log.AEEmrgConsLFO;
            case FuelType.MGO:
                return log.AEEmrgConsMGO;
            case FuelType.MDO:
                return log.AEEmrgConsMDO;
            case FuelType.LSHFO:
                return log.AEEmrgConsLSHFO;
            case FuelType.LSLFO:
                return log.AEEmrgConsLSLFO;
            case FuelType.LSMGO:
                return log.AEEmrgConsLSMGO;
            case FuelType.ULSFO2020:
                return log.AEEmrgConsULSFO2020;
            case FuelType.ULSLFO2020:
                return log.AEEmrgConsULSLFO2020;
            case FuelType.ULSMDO2020:
                return log.AEEmrgConsULSMDO2020;
            case FuelType.ULSMGO2020:
                return log.AEEmrgConsULSMGO2020;
            case FuelType.VLSFO2020:
                return log.AEEmrgConsVLSFO2020;
            case FuelType.VLSLFO2020:
                return log.AEEmrgConsVLSLFO2020;
            case FuelType.LPGP:
                return log.AEEmrgConsLPGP;
            case FuelType.LPGB:
                return log.AEEmrgConsLPGB;
            case FuelType.LNG:
                return log.AEEmrgConsLNG;
            case FuelType.Methanol:
                return log.AEEmrgConsM;
            case FuelType.Ethanol:
                return log.AEEmrgConsE;
            default:
                return 0f;
        }
    }

    #endregion 应急油耗
}

/// <summary>
/// 获取机组油耗的 LogAbstractExtensions
/// </summary>
public static class LogAbstractForUnitsExtensions
{
    /// <summary>
    /// 根据 fuelType 获取 ME 油耗（不含应急油耗，主机暂时没有应急油耗）
    /// </summary>
    /// <param name="log"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public static float GetMEConsumptionByFuelType(this LogAbstract log, FuelType fuelType)
    {
        switch (fuelType)
        {
            case FuelType.HFO:
                return log.MEConsumptionHFO;
            case FuelType.LFO:
                return log.MEConsumptionLFO;
            case FuelType.MGO:
                return log.MEConsumptionMGO;
            case FuelType.MDO:
                return log.MEConsumptionMDO;
            case FuelType.LSHFO:
                return log.MEConsumptionLSHFO;
            case FuelType.LSLFO:
                return log.MEConsumptionLSLFO;
            case FuelType.LSMGO:
                return log.MEConsumptionLSMGO;
            case FuelType.ULSFO2020:
                return log.MEConsumptionULSFO2020;
            case FuelType.ULSLFO2020:
                return log.MEConsumptionULSLFO2020;
            case FuelType.ULSMDO2020:
                return log.MEConsumptionULSMDO2020;
            case FuelType.ULSMGO2020:
                return log.MEConsumptionULSMGO2020;
            case FuelType.VLSFO2020:
                return log.MEConsumptionVLSFO2020;
            case FuelType.VLSLFO2020:
                return log.MEConsumptionVLSLFO2020;
            case FuelType.LPGP:
                return log.MEConsumptionLPGP;
            case FuelType.LPGB:
                return log.MEConsumptionLPGB;
            case FuelType.LNG:
                return log.MEConsumptionLNG;
            case FuelType.Methanol:
                return log.MEConsumptionM;
            case FuelType.Ethanol:
                return log.MEConsumptionE;
            default:
                throw new Exception($"不支持的 FuelType {nameof(FuelType)}");
        }
    }
    
    /// <summary>
    /// 根据 fuelType 获取 ME 总油耗（不含应急油耗，主机暂时没有应急油耗）
    /// </summary>
    /// <param name="logs"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    public static float GetMEConsumptionByFuelType(this IEnumerable<LogAbstract> logs, FuelType fuelType)
    {
        float totalConsumption = 0;

        foreach (var log in logs)
        {
            totalConsumption += log.GetMEConsumptionByFuelType(fuelType);
        }

        return totalConsumption;
    }
    
    /// <summary>
    /// 根据 fuelType 获取 AE 总油耗（含应急油耗）
    /// </summary>
    /// <param name="log"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public static float GetAEConsumptionByFuelType(this LogAbstract log, FuelType fuelType)
    {
        switch (fuelType)
        {
            case FuelType.HFO:
                return log.AEConsumptionHFO + log.AEEmrgConsHFO;
            case FuelType.LFO:
                return log.AEConsumptionLFO + log.AEEmrgConsLFO;
            case FuelType.MGO:
                return log.AEConsumptionMGO + log.AEEmrgConsMGO;
            case FuelType.MDO:
                return log.AEConsumptionMDO + log.AEEmrgConsMDO;
            case FuelType.LSHFO:
                return log.AEConsumptionLSHFO + log.AEEmrgConsLSHFO;
            case FuelType.LSLFO:
                return log.AEConsumptionLSLFO + log.AEEmrgConsLSLFO;
            case FuelType.LSMGO:
                return log.AEConsumptionLSMGO + log.AEEmrgConsLSMGO;
            case FuelType.ULSFO2020:
                return log.AEConsumptionULSFO2020 + log.AEEmrgConsULSFO2020;
            case FuelType.ULSLFO2020:
                return log.AEConsumptionULSLFO2020 + log.AEEmrgConsULSLFO2020;
            case FuelType.ULSMDO2020:
                return log.AEConsumptionULSMDO2020 + log.AEEmrgConsULSMDO2020;
            case FuelType.ULSMGO2020:
                return log.AEConsumptionULSMGO2020 + log.AEEmrgConsULSMGO2020;
            case FuelType.VLSFO2020:
                return log.AEConsumptionVLSFO2020 + log.AEEmrgConsVLSFO2020;
            case FuelType.VLSLFO2020:
                return log.AEConsumptionVLSLFO2020 + log.AEEmrgConsVLSLFO2020;
            case FuelType.LPGP:
                return log.AEConsumptionLPGP + log.AEEmrgConsLPGP;
            case FuelType.LPGB:
                return log.AEConsumptionLPGB + log.AEEmrgConsLPGB;
            case FuelType.LNG:
                return log.AEConsumptionLNG + log.AEEmrgConsLNG;
            case FuelType.Methanol:
                return log.AEConsumptionM + log.AEEmrgConsM;
            case FuelType.Ethanol:
                return log.AEConsumptionE + log.AEEmrgConsE;
            default:
                throw new Exception($"不支持的 FuelType {nameof(FuelType)}");
        }
    }
    
    /// <summary>
    /// 根据 fuelType 获取 AE 总油耗（含应急油耗）
    /// </summary>
    /// <param name="logs"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    public static float GetAEConsumptionByFuelType(this IEnumerable<LogAbstract> logs, FuelType fuelType)
    {
        float totalConsumption = 0;

        foreach (var log in logs)
        {
            totalConsumption += log.GetAEConsumptionByFuelType(fuelType);
        }

        return totalConsumption;
    }
    
    /// <summary>
    /// 根据 fuelType 获取 Boiler 总油耗（不含应急油耗，锅炉暂时没有应急油耗）
    /// </summary>
    /// <param name="log"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public static float GetBoilerConsumptionByFuelType(this LogAbstract log, FuelType fuelType)
    {
        switch (fuelType)
        {
            case FuelType.HFO:
                return log.BoilerConsumptionHFO;
            case FuelType.LFO:
                return log.BoilerConsumptionLFO;
            case FuelType.MGO:
                return log.BoilerConsumptionMGO;
            case FuelType.MDO:
                return log.BoilerConsumptionMDO;
            case FuelType.LSHFO:
                return log.BoilerConsumptionLSHFO;
            case FuelType.LSLFO:
                return log.BoilerConsumptionLSLFO;
            case FuelType.LSMGO:
                return log.BoilerConsumptionLSMGO;
            case FuelType.ULSFO2020:
                return log.BoilerConsumptionULSFO2020;
            case FuelType.ULSLFO2020:
                return log.BoilerConsumptionULSLFO2020;
            case FuelType.ULSMDO2020:
                return log.BoilerConsumptionULSMDO2020;
            case FuelType.ULSMGO2020:
                return log.BoilerConsumptionULSMGO2020;
            case FuelType.VLSFO2020:
                return log.BoilerConsumptionVLSFO2020;
            case FuelType.VLSLFO2020:
                return log.BoilerConsumptionVLSLFO2020;
            case FuelType.LPGP:
                return log.BoilerConsumptionLPGP;
            case FuelType.LPGB:
                return log.BoilerConsumptionLPGB;
            case FuelType.LNG:
                return log.BoilerConsumptionLNG;
            case FuelType.Methanol:
                return log.BoilerConsumptionM;
            case FuelType.Ethanol:
                return log.BoilerConsumptionE;
            default:
                throw new Exception($"不支持的 FuelType {nameof(FuelType)}");
        }
    }
    
    /// <summary>
    /// 根据 fuelType 获取 Boiler 总油耗（不含应急油耗，锅炉暂时没有应急油耗）
    /// </summary>
    /// <param name="logs"></param>
    /// <param name="fuelType"></param>
    /// <returns></returns>
    public static float GetBoilerConsumptionByFuelType(this IEnumerable<LogAbstract> logs, FuelType fuelType)
    {
        float totalConsumption = 0;

        foreach (var log in logs)
        {
            totalConsumption += log.GetBoilerConsumptionByFuelType(fuelType);
        }

        return totalConsumption;
    }
}